/**
 * Copyright (C) 2011-2012 GreenSoft S.A.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ar.com.greensoft.jeecommons.web.jsf.searching;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;

import org.ajax4jsf.model.ExtendedDataModel;
import org.richfaces.component.SortOrder;

import ar.com.greensoft.neosystem.dao.searching.DtoSearchableDao;
import ar.com.greensoft.neosystem.dao.searching.EntityDto;
import ar.com.greensoft.neosystem.dao.searching.SortCriteria;
import ar.com.greensoft.neosystem.search.SearchFilter;

/**
 *
 * @author Jorge E. Villaverde
 * @since 1.0.0
 * @version 1.0.0
 */
public abstract class AbstractSearchFacadeBean<T, PK extends Serializable, Dto extends EntityDto> 
	implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -2712522264120957756L;
	
	private static final String SORT_PROPERTY_PARAMETER = "sortProperty";
	
	/**
	 * Filtro para la búsqueda
	 */
	private SearchFilter filter;
	
	/**
	 * Data Model
	 */
	private EntityDataModel<Dto> dataModel;
	/**
	 * Sort Orders
	 */
	private Map<String, SortOrder> sortsOrders;
	/**
	 * Sort Priorities
	 */
	private List<String> sortPriorities;
	/**
	 * Enable Multible Sorting
	 */
	private boolean multipleSorting = false;

	
	// -------------------- IMPLEMENTATION ------------------------------------
	
	@PostConstruct
	public void init() {
		this.sortsOrders = new HashMap<String, SortOrder>();
		this.sortPriorities = new ArrayList<String>();
	}
	
	public SearchFilter getFilter() {
		if(filter == null)
			this.filter = createSearchFilter();
		return filter;
	}

	public void search() {
		if(filter != null)
			filter.setSearchActive(true);
		if(this.dataModel != null)
			this.dataModel.reset();
	}
	
	public boolean isSearchActive() {
		if(filter == null)
			return false;
		return filter.isSearchActive();
	}
	
	public ExtendedDataModel<Dto> getDataModel() {
		if(this.dataModel == null){
			this.dataModel = new EntityDataModel<Dto>(getDtoSearchDao(), getFilter());
		}
		return dataModel;
	}

	//-------------------SORTING METHODS---------------------------------------

	public void sort() {
        String property = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(SORT_PROPERTY_PARAMETER);
        if (property != null) {
            SortOrder currentPropertySortOrder = sortsOrders.get(property);
            if (multipleSorting) {
                if (!sortPriorities.contains(property)) {
                    sortPriorities.add(property);
                }
            } else {
                sortsOrders.clear();
            }
            if (currentPropertySortOrder == null || currentPropertySortOrder.equals(SortOrder.descending)) {
                sortsOrders.put(property, SortOrder.ascending);
            } else {
                sortsOrders.put(property, SortOrder.descending);
            }
            this.dataModel.reset();
            this.dataModel.setSortCriterias(createSortCriteria());
        }
    }
 
    private List<SortCriteria> createSortCriteria() {
    	List<SortCriteria> ret = new ArrayList<SortCriteria>(sortsOrders.keySet().size());
    	for(String key : sortsOrders.keySet()){
    		SortOrder order = sortsOrders.get(key);
    		ret.add(new SortCriteria(key, order.equals(SortOrder.ascending)));
    	}
		return ret;
	}

	public void modeChanged(ValueChangeEvent event) {
        reset();
    }
 
    public void reset() {
        sortPriorities.clear();
        sortsOrders.clear();
    }
 
    public boolean isMultipleSorting() {
        return multipleSorting;
    }
 
    public void setMultipleSorting(boolean multipleSorting) {
        this.multipleSorting = multipleSorting;
    }
 
    public List<String> getSortPriorities() {
        return sortPriorities;
    }
 
    public Map<String, SortOrder> getSortsOrders() {
        return sortsOrders;
    }


	//-------------------ABSTRACT METHODS--------------------------------------
	protected abstract SearchFilter createSearchFilter();
	
	
	protected abstract DtoSearchableDao<Dto> getDtoSearchDao();
	
	
}
